﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace todolist
{
    public partial class TodolistForm : Form
    {
        public TodolistForm()
        {
            InitializeComponent();
        }

        List<Label> taskTextLabel = new List<Label>();
        List<Panel> taskPanel = new List<Panel>();
        List<CheckBox> taskCheckBox = new List<CheckBox>();
        List<Label> taskDueDateLabel = new List<Label>();
        List<Label> taskPriorityLabel = new List<Label>();
        List<PictureBox> taskDeletePictureBox = new List<PictureBox>();
        TasksEntities db = new TasksEntities();

        // Количество задач для вывода
        int r_count;
        // Индексы задач для рокировки
        int ind_1 = -1;
        int ind_2 = -1;

        // ===============================
        //  Рокировка
        // ===============================
        private void Replace(object sender, EventArgs e)
        {
            string panel_index = "";
            var panel = sender as Panel;
            Object parent = null;

            if (panel == null)
            {
                parent = sender.GetType().GetProperty("Parent").GetValue(sender, null);
                panel_index = parent.GetType().GetProperty("Name").GetValue(parent, null).ToString().Remove(0, 2);
            }
            else
            {
                panel_index = panel.Name.Remove(0, 2);
            }
            
            int ind = Convert.ToInt32(panel_index);

            // Выделение первой задачи
            if (ind_1 < 0)
            {
                if (panel == null)
                {
                    parent.GetType().GetProperty("BackColor").SetValue(parent, SystemColors.ControlDark, null);
                }
                else
                {
                    panel.BackColor = SystemColors.ControlDark;
                    foreach (var item in panel.Controls)
                    {
                        item.GetType().GetProperty("BackColor").SetValue(item, SystemColors.ControlDark, null);
                    }
                }
                this.Refresh();
                ind_1 = ind;
                return;
            }

            // Выделение второй задачи
            if (ind_1 >= 0 && ind_2 < 0)
            {
                if (ind_1 == ind)
                {
                    // Отмена выделения
                    if (panel == null)
                    {
                        parent.GetType().GetProperty("BackColor").SetValue(parent, SystemColors.ActiveCaption, null);
                    }
                    else
                    {
                        panel.BackColor = SystemColors.ActiveCaption;
                        foreach (var item in panel.Controls)
                        {
                            item.GetType().GetProperty("BackColor").SetValue(item, SystemColors.ActiveCaption, null);
                        }
                    }

                    this.Refresh();
                    ind_1 = -1;
                    return;
                }

                if (panel == null)
                {
                    parent.GetType().GetProperty("BackColor").SetValue(parent, SystemColors.ControlDark, null);
                }
                else
                {
                    panel.BackColor = SystemColors.ControlDark;
                    foreach (var item in panel.Controls)
                    {
                        item.GetType().GetProperty("BackColor").SetValue(item, SystemColors.ControlDark, null);
                    }
                }

                this.Refresh();
                tasksListPanel.ScrollControlIntoView(taskPanel[ind]);

                ind_2 = ind;

                foreach (var item in db.Tasks)
                {
                    if (item.index_number == ind_1)
                    {
                        item.index_number = ind_2;
                        db.SaveChanges();
                        continue;
                    }
                    if (item.index_number == ind_2)
                    {
                        item.index_number = ind_1;
                        db.SaveChanges();
                    }
                }

                SuspendUpdate.Suspend(tasksListGroupbox);
                DeleteList();
                RefreshList();
                SuspendUpdate.Resume(tasksListGroupbox);
                this.Refresh();
                tasksListPanel.ScrollControlIntoView(taskPanel[ind]);

                ind_1 = -1;
                ind_2 = -1;
            }
        }

        // ===============================
        //  Удаление списка задач с формы
        // ===============================
        private void DeleteList()
        {
            int i = 0;
            foreach (var item in db.Tasks)
            {
                if (item.actual_date == null)
                {
                    string cn = "tp" + i.ToString();
                    this.Controls.RemoveByKey(cn);
                    taskPanel[i].Dispose();
                    i++;
                }
            }

            r_count = i - 2;

            taskTextLabel.Clear();
            taskPanel.Clear();
            taskCheckBox.Clear();
            taskDueDateLabel.Clear();
            taskPriorityLabel.Clear();
            taskDeletePictureBox.Clear();
        }

        // ===============================
        //  Удаление задачи
        // ===============================
        private void DeleteTask(object sender, EventArgs e)
        {
            bool del = false;

            DialogResult result = MessageBox.Show("Удалить задачу?", "Подтверждение удаления", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);

            if (result.ToString() == "Yes")
            {
                del = true;
            }

            if (del)
            {
                var picturebox = (PictureBox)sender;
                string control_index = picturebox.Name.Remove(0, 2);

                SuspendUpdate.Suspend(tasksListGroupbox);
                DeleteList();

                int i = Convert.ToInt32(control_index);
                foreach (var item in db.Tasks)
                {
                    if (item.index_number == i)
                    {
                        db.Tasks.Remove(item);
                        db.SaveChanges();
                    }
                    if (item.index_number > i)
                    {
                        item.index_number--;
                        db.SaveChanges();
                    }
                }
                RefreshList();
                SuspendUpdate.Resume(tasksListGroupbox);
                this.Refresh();

                if (i < r_count)
                {
                    tasksListPanel.ScrollControlIntoView(taskPanel[i]);
                }
                else if (r_count > 0)
                {
                    tasksListPanel.ScrollControlIntoView(taskPanel[i - 1]);
                }
            }          
        }

        // ===============================
        //  Выполнение задачи
        // ===============================
        private void CheckTask(object sender, EventArgs e)
        {
            var checkbox = (CheckBox)sender;
            string control_index = checkbox.Name;

            SuspendUpdate.Suspend(tasksListGroupbox);
            DeleteList();

            int i = Convert.ToInt32(control_index);
            foreach (var item in db.Tasks)
            {
                if (item.index_number == i)
                {
                    item.actual_date = DateTime.Now;
                    item.index_number = -1;
                    db.SaveChanges();
                }
                if (item.index_number > i)
                {
                    item.index_number--;
                    db.SaveChanges();
                }
            }

            RefreshList();

            SuspendUpdate.Resume(tasksListGroupbox);
            this.Refresh();
            
            if (i < r_count)
            {
                tasksListPanel.ScrollControlIntoView(taskPanel[i]);
            }
            else if (r_count > 0)
            {
                tasksListPanel.ScrollControlIntoView(taskPanel[i-1]);
            }
        }

        // ===============================
        //  Вывод списка задач на форму
        // ===============================
        private void RefreshList()
        {
            var sortedNames =
                from n in db.Tasks
                orderby n.index_number
                select n;

            int i = 0;
            foreach (var item in sortedNames)
            {
                if (item.actual_date == null)
                {
                    // taskTextLabel
                    taskTextLabel.Add (new Label());
                    taskTextLabel[i].Size = new System.Drawing.Size(180, 30);
                    taskTextLabel[i].Location = new System.Drawing.Point(25, 7);
                    taskTextLabel[i].BackColor = SystemColors.ActiveCaption;
                    taskTextLabel[i].TextAlign = ContentAlignment.MiddleLeft;
                    taskTextLabel[i].Anchor = (AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right);
                    taskTextLabel[i].MaximumSize = new System.Drawing.Size(180, 30);
                    taskTextLabel[i].Text = item.text;
                    taskTextLabel[i].Click += new System.EventHandler((sender, e) => Replace(sender, e));

                    // Panel
                    taskPanel.Add(new Panel());
                    taskPanel[i].Parent = tasksListPanel;
                    taskPanel[i].Size = new System.Drawing.Size(467, 42);
                    taskPanel[i].Location = new System.Drawing.Point(3, 9 + 48 * i);
                    taskPanel[i].BackColor = SystemColors.ActiveCaption;
                    taskPanel[i].Anchor = (AnchorStyles.Top | AnchorStyles.Left);
                    taskPanel[i].Controls.Add(taskTextLabel[i]);
                    taskPanel[i].Name = "tp" + i.ToString();
                    taskPanel[i].Click += new System.EventHandler((sender, e) => Replace(sender, e));

                    // CheckBox
                    taskCheckBox.Add(new CheckBox());
                    taskCheckBox[i].Size = new System.Drawing.Size(15, 14);
                    taskCheckBox[i].Location = new System.Drawing.Point(6, 14);
                    taskCheckBox[i].BackColor = SystemColors.ActiveCaption;
                    taskCheckBox[i].UseVisualStyleBackColor = true;
                    taskPanel[i].Controls.Add(taskCheckBox[i]);
                    taskCheckBox[i].Name = i.ToString();
                    taskCheckBox[i].CheckedChanged += new System.EventHandler((sender, e) => CheckTask(sender, e));

                    // DueDateLabel
                    taskDueDateLabel.Add(new Label());
                    taskDueDateLabel[i].Size = new System.Drawing.Size(70, 13);
                    taskDueDateLabel[i].Location = new System.Drawing.Point(225, 14);
                    taskDueDateLabel[i].BackColor = SystemColors.ActiveCaption;
                    taskDueDateLabel[i].Anchor = (AnchorStyles.Top | AnchorStyles.Right);
                    taskDueDateLabel[i].Text = item.due_date.ToString().Remove(10);
                    taskPanel[i].Controls.Add(taskDueDateLabel[i]);
                    taskDueDateLabel[i].Click += new System.EventHandler((sender, e) => Replace(sender, e));

                    // PriorityLabel
                    taskPriorityLabel.Add(new Label());
                    taskPriorityLabel[i].Size = new System.Drawing.Size(110, 13);
                    taskPriorityLabel[i].Location = new System.Drawing.Point(307, 14);
                    taskPriorityLabel[i].BackColor = SystemColors.ActiveCaption;
                    taskPriorityLabel[i].Anchor = (AnchorStyles.Top | AnchorStyles.Right);
                    taskPriorityLabel[i].Click += new System.EventHandler((sender, e) => Replace(sender, e));

                    if (item.priority == 0)
                        taskPriorityLabel[i].Text = "Низкий приоритет";
                    else if (item.priority == 1)
                        taskPriorityLabel[i].Text = "Средний приоритет";
                    else if (item.priority == 2)
                        taskPriorityLabel[i].Text = "Высокий приоритет";

                    taskPanel[i].Controls.Add(taskPriorityLabel[i]);

                    // PictureBox
                    taskDeletePictureBox.Add(new PictureBox());
                    taskDeletePictureBox[i].Image = todolist.Properties.Resources.del_icon_18x18;
                    taskDeletePictureBox[i].Size = new System.Drawing.Size(23, 23);
                    taskDeletePictureBox[i].Location = new System.Drawing.Point(433, 11);
                    taskDeletePictureBox[i].BackColor = SystemColors.ActiveCaption;
                    taskDeletePictureBox[i].Anchor = (AnchorStyles.Top | AnchorStyles.Right);
                    taskPanel[i].Controls.Add(taskDeletePictureBox[i]);
                    taskDeletePictureBox[i].Name = "pb" + i.ToString();
                    taskDeletePictureBox[i].Click += new System.EventHandler((sender, e) => DeleteTask(sender, e));

                    i++;
                }
            }
        }

        // ===============================
        //  ЗАГРУЗКА ФОРМЫ
        // ===============================
        private void Form1_Load(object sender, EventArgs e)
        {
            // Приоритет по умолчанию - средний
            newTaskPriorityComboBox.SelectedIndex = 1;

            string overdue_tasks = "";

            var sortedNames =
                from n in db.Tasks
                orderby n.index_number
                select n;

            foreach (var item in sortedNames)
            {
                if (item.actual_date == null && item.due_date < DateTime.Now)
                {
                    overdue_tasks += item.text + ' ' + '(' + item.due_date.ToString().Remove(10) + ')' + '\n';
                }
            }

            if (overdue_tasks != "")
            {
                MessageBox.Show(overdue_tasks, "Просроченные задачи");
            }

            RefreshList();
        }

        // ===============================
        //  Вызов окна статистики
        // ===============================
		private void статистикаToolStripMenuItem_Click(object sender, EventArgs e)
		{
            Form statForm = new StatisticsForm();
            statForm.Show();
		}

        // ===============================
        //  Добавление задачи
        // ===============================
        private void button1_Click(object sender, EventArgs e)
        {
            if (newTaskTextBox.Text.Length == 0)
            {
                MessageBox.Show("Введите текст задачи!", "Некорректный ввод", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
            
            else if (newTaskTextBox.Text.Length > 55)
            {
                MessageBox.Show("Текст задачи должен быть не длиннее 55 символов. Текущая длина - " + newTaskTextBox.Text.Length.ToString() + ".", "Некорректный ввод", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
            else
            {
                this.DoubleBuffered = true;
                SuspendUpdate.Suspend(tasksListGroupbox);
                DeleteList();
                tasksListGroupbox.Update();

                int rows_count = 0;
                foreach (var item in db.Tasks)
                {
                    if (item.actual_date == null)
                    {
                        rows_count++;
                    }
                }

                var task = new Task { text = newTaskTextBox.Text, due_date = NewTaskDueDateTimePicker.Value, priority = newTaskPriorityComboBox.SelectedIndex, index_number = rows_count, added_date = DateTime.Now };
                db.Tasks.Add(task);
                db.SaveChanges();
                newTaskTextBox.Text = "";

                RefreshList();
                SuspendUpdate.Resume(tasksListGroupbox);
                this.Refresh();
                tasksListPanel.ScrollControlIntoView(taskPanel[taskPanel.Count-1]);
            } 
        }

        // ===============================
        //  Вызов информации о программе
        // ===============================
        private void оПрограммеToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show("«Диспетчер дел» помогает держать под контролем список дел, определять сроки и расставлять приоритеты. Может использоваться как вспомогательное средство для личного тайм-менеджмента.\n\n© НИ ТПУ, 2014.\n© Кустов Денис Анатольевич, Соболева Екатерина Сергеевна, 2014.", "Диспетчер дел - О программе");
        }

        // ===============================
        //  Вызов помощи
        // ===============================
        private void помощьToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Для добавления задачи в базу данных необходимо ввести текст задачи.\nДля перемещения нужно выбрать любые две задачи нажатием по ним левой кнопкой мыши, и после этого они поменяются местами. \nДля удаления задачи нужно нажать на пиктограмму в виде мусорного бака. \nЧтобы отметить выполнение, нужно поставить галочку напротив соответствующей задачи. \nДля вызова статистики нужно нажать на кнопку «Статистика». Можно задать временной интервал, для которого необходимо посмотреть статистику.", "Диспетчер дел - Помощь");
        }
    }

    // ===============================
    //  Приостановка перерисовки
    // ===============================
    public static class SuspendUpdate
    {
        private const int WM_SETREDRAW = 0x000B;

        public static void Suspend(Control control)
        {
            Message msgSuspendUpdate = Message.Create(control.Handle, WM_SETREDRAW, IntPtr.Zero,
                IntPtr.Zero);

            NativeWindow window = NativeWindow.FromHandle(control.Handle);
            window.DefWndProc(ref msgSuspendUpdate);
        }

        public static void Resume(Control control)
        {
            IntPtr wparam = new IntPtr(1);
            Message msgResumeUpdate = Message.Create(control.Handle, WM_SETREDRAW, wparam,
                IntPtr.Zero);

            NativeWindow window = NativeWindow.FromHandle(control.Handle);
            window.DefWndProc(ref msgResumeUpdate);

            control.Invalidate();
        }
    }
}